// ffmpeg.worker.ts
import { FFmpeg } from '@ffmpeg/ffmpeg'
import { fetchFile, toBlobURL } from '@ffmpeg/util'

const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.9/dist/esm'
const ffmpeg = new FFmpeg()
let isRunning = false
let ffmpegLogs = ''

// 解析时间字符串为秒数
function parseDuration(timeStr: string): number {
  const parts = timeStr.split(':').map(Number)
  if (parts.length === 1) return parts[0]
  if (parts.length === 2) return parts[0] * 60 + parts[1]
  return parts[0] * 3600 + parts[1] * 60 + parts[2]
}

// 发送日志消息到主线程
function log(message: string) {
  ffmpegLogs += message + '\n'
  self.postMessage({ type: 'log', data: message })
}

// 发送进度消息到主线程
function updateProgress(progress: number, message: string) {
  self.postMessage({ type: 'progress', data: { progress, message } })
}

// 从FFmpeg文件系统中删除文件（增强兼容性）
async function removeFile(filePath: string) {
  try {
    // 尝试使用FS API
    if (typeof ffmpeg.FS === 'function') {
      ffmpeg.FS('unlink', filePath)
      log(`Deleted file: ${filePath}`)
    } else {
      // 备选方法：使用FFmpeg命令删除
      await ffmpeg.exec(['-y', '-i', 'dummy', '-f', 'lavfi', '-t', '0.1', '-c:v', 'rawvideo', '-pix_fmt', 'yuv420p', filePath])
      log(`Deleted file ${filePath} using fallback method`)
    }
  } catch (error) {
    log(`Error deleting file ${filePath}: ${(error as Error).message}`)
  }
}

// 监控内存使用情况
function logMemoryUsage() {
  if (typeof performance !== 'undefined' && performance.memory) {
    const memory = performance.memory
    const usedMB = memory.usedJSHeapSize / 1024 / 1024
    const totalMB = memory.totalJSHeapSize / 1024 / 1024
    log(`Memory usage: ${usedMB.toFixed(2)}MB / ${totalMB.toFixed(2)}MB`)
  }
}

// 主处理函数
async function processVideo(videoURL: string) {
  try {
    isRunning = true
    updateProgress(0, 'Loading FFmpeg core...')

    await ffmpeg.load({
      coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
      wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),
      workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript'),
      wasmOptions: {
        initialMemory: 8192, // 512MB
        maximumMemory: 32768 // 2GB
      }
    })

    ffmpeg.on('log', ({ type, message }: any) => {
      ffmpegLogs += `[${type}] ${message}\n`
      log(`[FFmpeg] ${message}`)
    })

    log('FFmpeg loaded successfully')
    updateProgress(5, 'Downloading video...')

    const videoData = await fetchFile(videoURL)
    await ffmpeg.writeFile('input.mp4', videoData)
    log('Video downloaded and written to FFmpeg filesystem')

    updateProgress(10, 'Analyzing video metadata...')
    try {
      await ffmpeg.exec(['-i', 'input.mp4'])
    } catch (e) {
      log('Video metadata analysis completed')
    }

    log('Extracting video duration...')
    const durationMatch = ffmpegLogs.match(
      /Duration:\s*(\d+:\d+:\d+\.\d+|\d+\.\d+s?)/i
    )

    if (!durationMatch) {
      log('Failed to get duration from logs, using fallback (60 seconds)')
      throw new Error('Failed to get video duration')
    }

    const totalDuration = parseDuration(durationMatch[1].replace('s', ''))
    log(`Video duration: ${totalDuration} seconds`)

    // 优化：减小片段长度以降低内存压力
    const segmentDuration = 5 // 每段5秒（原为10秒）
    const segmentCount = Math.ceil(totalDuration / segmentDuration)
    log(`Splitting into ${segmentCount} segments of ${segmentDuration} seconds each`)

    // 处理每个片段
    for (let i = 0; i < segmentCount && isRunning; i++) {
      const startTime = i * segmentDuration
      const segmentName = `segment_${i}.mp4`
      const processedName = `processed_${i}.mp4`

      updateProgress(10 + (80 * i / segmentCount), `Processing segment ${i + 1}/${segmentCount}`)

      // 提取片段
      log(`Extracting segment ${i + 1}/${segmentCount} (${startTime}s to ${startTime + segmentDuration}s)`)
      await ffmpeg.exec([
        '-i', 'input.mp4',
        '-ss', startTime.toString(),
        '-t', segmentDuration.toString(),
        '-c', 'copy',
        segmentName
      ])

      // 释放输入视频占用的内存（第一个片段处理后）
      if (i === 0) {
        removeFile('input.mp4')
        log('Released input video from memory')
      }

      // 监控内存使用
      logMemoryUsage()

      // 转码片段（进一步优化内存参数）
      log(`Transcoding segment ${i + 1}/${segmentCount}`)

      // 根据内存情况选择不同的转码策略
      const memoryIntensive = totalDuration > 300 // 视频超过5分钟使用低内存策略

      if (memoryIntensive) {
        // 低内存策略：直接复制视频流，不重新编码
        await ffmpeg.exec([
          '-i', segmentName,
          '-c:v', 'copy',
          '-c:a', 'copy',
          processedName
        ])
        log('Using copy-only strategy to reduce memory usage')
      } else {
        // 高质量策略：使用优化的编码参数
        await ffmpeg.exec([
          '-i', segmentName,
          '-c:v', 'libx264',
          '-crf', '18', // 高质量
          '-preset', 'ultrafast', // 更快的预设，减少内存使用
          '-threads', '1', // 单线程
          '-tile-columns', '0',
          '-slice-max-size', '1000K',
          '-bufsize', '1000K',
          '-maxrate', '1000K',
          '-c:a', 'aac',
          '-b:a', '64k', // 降低音频质量
          processedName
        ])
      }

      // 删除原始片段以释放内存
      removeFile(segmentName)

      // 强制垃圾回收（如果支持）
      if (typeof gc === 'function') {
        gc()
        log('Forced garbage collection')
      }

      // 再次监控内存使用
      logMemoryUsage()
    }

    if (!isRunning) return

    // 合并片段
    let segmentListContent = ''
    for (let i = 0; i < segmentCount; i++) {
      segmentListContent += `file 'processed_${i}.mp4'\n`
    }
    await ffmpeg.writeFile('segments.txt', new TextEncoder().encode(segmentListContent))

    updateProgress(90, 'Merging segments...')
    log('Merging all segments into final video')
    await ffmpeg.exec([
      '-f', 'concat',
      '-safe', '0',
      '-i', 'segments.txt',
      '-c', 'copy', // 直接复制，不重新编码
      'output.mp4'
    ])

    // 删除处理后的片段文件
    for (let i = 0; i < segmentCount; i++) {
      removeFile(`processed_${i}.mp4`)
    }
    removeFile('segments.txt')

    // 读取输出文件
    const data = await ffmpeg.readFile('output.mp4')
    updateProgress(100, 'Transcoding completed!')
    self.postMessage({ type: 'complete', data })

  } catch (error) {
    const errorMsg = (error as Error).message
    log(`Error: ${errorMsg}`)

    // 尝试备选处理方法
    if (errorMsg.includes('OOM') || errorMsg.includes('memory')) {
      log('Switching to fallback low-memory processing...')
      await fallbackProcess()
      return
    }

    self.postMessage({ type: 'error', data: errorMsg })
  } finally {
    isRunning = false
    try {
      await ffmpeg.terminate()
    } catch (e) {
      log(`Error releasing FFmpeg: ${(e as Error).message}`)
    }
  }
}

// 备选处理函数（当无法获取时长或内存不足时）
async function fallbackProcess() {
  const fixedSegments = 10 // 增加分段数量，减少每段大小
  const segmentDuration = 5 // 每段5秒

  log(`Fallback: processing with ${fixedSegments} segments of ${segmentDuration} seconds each`)

  for (let i = 0; i < fixedSegments && isRunning; i++) {
    const startTime = i * segmentDuration
    const segmentName = `segment_${i}.mp4`
    const processedName = `processed_${i}.mp4`

    updateProgress(10 + (80 * i / fixedSegments), `Fallback: Processing segment ${i + 1}/${fixedSegments}`)

    // 提取片段
    await ffmpeg.exec([
      '-i', 'input.mp4',
      '-ss', startTime.toString(),
      '-t', segmentDuration.toString(),
      '-c', 'copy',
      segmentName
    ])

    // 低内存策略：直接复制视频流
    await ffmpeg.exec([
      '-i', segmentName,
      '-c:v', 'copy',
      '-c:a', 'copy',
      processedName
    ])

    removeFile(segmentName)
    logMemoryUsage()
  }

  // 合并片段
  let segmentListContent = ''
  for (let i = 0; i < fixedSegments; i++) {
    segmentListContent += `file 'processed_${i}.mp4'\n`
  }
  await ffmpeg.writeFile('segments.txt', new TextEncoder().encode(segmentListContent))

  await ffmpeg.exec([
    '-f', 'concat',
    '-safe', '0',
    '-i', 'segments.txt',
    '-c', 'copy',
    'output.mp4'
  ])

  // 删除临时文件
  for (let i = 0; i < fixedSegments; i++) {
    removeFile(`processed_${i}.mp4`)
  }
  removeFile('segments.txt')

  const data = await ffmpeg.readFile('output.mp4')
  updateProgress(100, 'Fallback transcoding completed! (lower quality)')
  self.postMessage({ type: 'complete', data })
}

// 监听主线程消息
self.onmessage = (e) => {
  const { type, videoURL } = e.data
  if (type === 'start') {
    processVideo(videoURL)
  } else if (type === 'cancel') {
    isRunning = false
  }
}